package com.ccl.iot.views;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.GridView;

import com.ccl.iot.device.IOTMultiFunc5525;

import java.util.ArrayList;

public abstract class ItemGridView<TYPE> extends GridView {
	private static final int KMESSAGE_ADD_ITEM = 1;
	private static final int KMESSAGE_REMOVE_ITEM = 2;
	private static final int KMESSAGE_SET_CHECKED = 3;

	public interface OnItemChangeListener<TYPE> {
		public void onNewItem(ItemView<TYPE> aView, TYPE aItem);

		public void onRemoveItem(ItemView<TYPE> aView, TYPE aItem);
	}

	public interface OnItemCheckChangeListener<TYPE> {
		public void onItemCheckChange(ItemView<TYPE> aView, TYPE aItem, boolean aChecked);
	}

	public interface OnItemClickListenerr<TYPE> {
		public void onItemClick(ItemView<TYPE> aView, TYPE aItem);
	}

	public interface OnItemLongClickListener<TYPE> {
		public void onItemLongClick(ItemView<TYPE> aView, TYPE aItem);
	}

	public static enum TCHOICE_MODE {
		;
		public static final int ECHOICE_MODE_NONE = 0;
		public static final int ECHOICE_MODE_SINGLE = 1;
		public static final int ECHOICE_MODE_MULTIPLE = 2;
	}

	private Thread iMainThread = null;
	private int iChoiceMode = TCHOICE_MODE.ECHOICE_MODE_NONE;

	/*private int iWidth = 0;
	private int iHeight = 0;
	private int iRows = 0;
	private int iColumns = 0;
	private int iItemWidth = 0;
	private int iItemHeight = 0;*/

	private ArrayList<TYPE> iItems = null;
	private ArrayList<ItemView<TYPE>> iItemViews = null;

	public ItemGridView(Context context, int aChoiceMode) {
		super(context);

		iMainThread = Thread.currentThread();

		iChoiceMode = aChoiceMode;

	}

	public int getItemCount() {
		if (iItems != null) {
			return iItems.size();
		}

		return 0;
	}

	public ArrayList<TYPE> getItemList() {
		ArrayList<TYPE> newList;
		newList = (iItems == null) ? null : new ArrayList<TYPE>(iItems);
		/*if (iItems != null) {
			for (TYPE aItem : iItems) {
				if ((aItem instanceof IOTMultiFunc5525) && ((IOTMultiFunc5525) aItem).hasPatch()) {
					if (iItems.contains(aItem)) {
						newList.remove(aItem);
					}
				}
			}
		}*/

		if (newList != null && newList.size() > 0) {
			int size = newList.size();
			for (int i = 0; i < size; i++) {
				TYPE type = newList.get(i);
				if ((type instanceof IOTMultiFunc5525) && ((IOTMultiFunc5525) type).hasPatch()) {
					newList.remove(type);
					i--;
					size--;
				}
			}
		}

		return newList;
	}

	public ArrayList<ItemView<TYPE>> getItemViewList() {
		return iItemViews;
	}

	private Handler iHandler = new Handler() {
		@SuppressWarnings("unchecked")
		@Override
		public void handleMessage(Message msg) {
			if (msg != null && msg.obj != null) {
				if (msg.what == KMESSAGE_ADD_ITEM) {
					addItem((TYPE) msg.obj);
				} else if (msg.what == KMESSAGE_REMOVE_ITEM) {
					removeItem((TYPE) msg.obj);
				} else if (msg.obj instanceof ItemView<?>) {
					boolean tChecked = (msg.what == KMESSAGE_SET_CHECKED);

					((ItemView<TYPE>) msg.obj).setChecked(tChecked);
				}
			}
		}
	};

	private ArrayList<TYPE> iCheckedItems = null;

	public boolean isChecked(TYPE aItem) {
		if (aItem != null && iCheckedItems != null) {
			return iCheckedItems.contains(aItem);
		}

		return false;
	}

	public ArrayList<TYPE> getCheckedItems() {
		if (iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE) {
			if (iCheckedItems != null && iCheckedItems.size() > 0) {
				return iCheckedItems;
			}
		}

		return null;
	}

	public void addCheckedItem(TYPE aItem) {
		if (aItem != null && iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE) {
			if (iCheckedItems == null) {
				iCheckedItems = new ArrayList<TYPE>();
			} else {
				synchronized (iCheckedItems) {
					if (iCheckedItems.contains(aItem)) {
						return;
					}
				}
			}

			synchronized (iCheckedItems) {
				if(iChoiceMode == TCHOICE_MODE.ECHOICE_MODE_NONE){
					iCheckedItems.clear();
				}
				if (iCheckedItems.add(aItem) == false) {
					return;
				}
			}

			if (iItems != null && iItems.contains(aItem) && iItemViews != null) {
				int tIndex = iItems.indexOf(aItem);

				if (tIndex >= 0 && tIndex < iItemViews.size()) {
					ItemView<TYPE> tItem = iItemViews.get(tIndex);

					if (tItem != null) {
						if (tItem.isChecked() == false) {
							if (Thread.currentThread() == iMainThread) {
								tItem.setChecked(true);
							} else {
								if (iHandler.hasMessages(KMESSAGE_SET_CHECKED, tItem) == false) {
									iHandler.sendMessage(Message.obtain(iHandler, KMESSAGE_SET_CHECKED, tItem));
								}
							}
						}
					}
				}
			} else {
				addItem(aItem);
			}
		}
	}

	public void addCheckedItems(ArrayList<TYPE> aItems) {
		if (aItems != null) {
			for (int i = 0, tCount = aItems.size(); i < tCount; i++) {
				addCheckedItem(aItems.get(i));
			}
		}
	}

	private ArrayList<OnItemChangeListener<TYPE>> iItemChangeListeners = null;

	public void setOnItemChangeListener(OnItemChangeListener<TYPE> aListener) {
		if (iItemChangeListeners == null) {
			iItemChangeListeners = new ArrayList<ItemGridView.OnItemChangeListener<TYPE>>();
		}
		iItemChangeListeners.add(aListener);
	}

	protected abstract ItemView<TYPE> getItemView(TYPE aItem);

	public boolean containsItem(TYPE aItem) {
		if (aItem != null && iItems != null) {
			return iItems.contains(aItem);
		}

		return false;
	}

	/*public boolean addItem(TYPE aItem) {
		if (aItem != null) {
			if (iItems == null) {
				iItems = new ArrayList<TYPE>();
			} else if (iItems.contains(aItem)) {
				return false;
			}

			if (Thread.currentThread() == iMainThread) {
				if (iItems.add(aItem)) {

					ItemView<TYPE> tView = genItemView(aItem);

					if (tView != null) {
						if (iItemViews == null) {
							iItemViews = new ArrayList<ItemView<TYPE>>();
						}
						if (iItemViews.add(tView)) {
							if (iItemChangeListeners != null) {
								for (OnItemChangeListener<TYPE> listener : iItemChangeListeners) {
									listener.onNewItem(tView, aItem);
								}
							}

							if (iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE) {
								tView.setCheckable(true);

								if (iCheckedItems != null) {
									synchronized (iCheckedItems) {
										if (iCheckedItems.contains(aItem)) {
											iHandler.removeMessages(KMESSAGE_SET_CHECKED, aItem);

											tView.setChecked(true);
										}
									}
								}
							}

							handleViewEvent(tView, false);

							// this.addView(tView);

							iNeedToRefresh = true;

							return true;
						}
					}

					iItems.remove(aItem);
				}
			} else {
				iHandler.removeMessages(KMESSAGE_REMOVE_ITEM, aItem);

				if (iHandler.hasMessages(KMESSAGE_ADD_ITEM, aItem) == false) {
					iHandler.sendMessage(Message.obtain(iHandler, KMESSAGE_ADD_ITEM, aItem));
				}
			}
		}

		return false;
	}*/

	// =====================modify start================================
	public boolean addItem(TYPE aItem) {
		if (aItem != null) {
			if (iItems == null) {
				iItems = new ArrayList<TYPE>();
			} else if (iItems.contains(aItem)) {
				return false;
			}

			if (iItems.add(aItem)) {
				for (OnItemChangeListener<TYPE> listener : iItemChangeListeners) {
					listener.onNewItem(null, aItem);
				}
			}

			return true;

		}

		return false;
	}

	public ItemView<TYPE> buildView(TYPE item) {

		ItemView<TYPE> tView = getItemView(item);

		if (tView != null) {

			if (iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE) {
				tView.setCheckable(true);

				if (iCheckedItems != null) {
					synchronized (iCheckedItems) {
						if (iCheckedItems.contains(item)) {
							tView.setChecked(true);
						}
					}
				}
			}

			handleViewEvent(tView, false);

			return tView;
		}

		return null;
	}

	// =====================modify end================================

	public boolean removeItem(TYPE aItem) {
		if (aItem != null && iItems != null) {
			int tIndex = iItems.indexOf(aItem);

			/* if (tIndex >= 0 && tIndex < iItemViews.size()){ ItemView<TYPE> tView = iItemViews.get(tIndex);
			 * 
			 * if (iCheckedItems != null){ //Can't remove checked item synchronized(iCheckedItems){ if (iCheckedItems.contains(aItem)){ return false; } } } */

			// ==============start==============
			if (tIndex >= 0) {
				ItemView<TYPE> tView = null;
				synchronized (this) {
					if (iItemViews != null && tIndex < iItemViews.size()) {
						tView = iItemViews.get(tIndex);
					}
				}

				if (iCheckedItems != null) { // Can't remove checked item
					synchronized (iCheckedItems) {
						if (iCheckedItems.contains(aItem)) {
							return false;
						}
					}
				}
				// ==============end==============

				if (Thread.currentThread() == iMainThread) {
					if (iItems.remove(aItem)) {
						if (iItemViews != null) {

							if (tView != null) {
								iItemViews.remove(tIndex);

								handleViewEvent(tView, true);

								this.removeView(tView);

								if (iItemChangeListeners != null) {
									for (OnItemChangeListener<TYPE> listener : iItemChangeListeners) {
										listener.onRemoveItem(tView, aItem);
									}
								}
							}

						}

						return true;
					}
				} else {
					iHandler.removeMessages(KMESSAGE_ADD_ITEM, aItem);

					if (iHandler.hasMessages(KMESSAGE_REMOVE_ITEM, aItem) == false) {
						iHandler.sendMessage(Message.obtain(iHandler, KMESSAGE_REMOVE_ITEM, aItem));
					}
				}
			}
		}

		return false;
	}

	private boolean iAutoCheckInSingleMode = false;

	private ItemView.OnItemCheckChangeListener<TYPE> iItemCheckChangeListener = new ItemView.OnItemCheckChangeListener<TYPE>() {
		@Override
		public boolean onItemCheckChange(ItemView<TYPE> aItem, boolean aChecked) {
			if (aItem != null) {
				if (iAutoCheckInSingleMode == false) {
					if (aChecked) {
						if (iChoiceMode == TCHOICE_MODE.ECHOICE_MODE_SINGLE) {
							if(iItemViews == null){
								iItemViews = new ArrayList<ItemView<TYPE>>();
							}
							iItemViews.add(aItem);
							if (iItemViews != null) {
								ItemView<TYPE> tView;
								iAutoCheckInSingleMode = true;

								for (int i = iItemViews.size() - 1; i >= 0; i--) {
									if ((tView = iItemViews.get(i)) != null && tView != aItem) {
										tView.setChecked(false);
										iItemViews.remove(tView);
										i--;
									}
								}

								iAutoCheckInSingleMode = false;
							}
						}
					}else{
						if(iItemViews != null && iItemViews.contains(aItem)){
							iItemViews.remove(aItem);
						}
					}

					if (iOnItemCheckChangeListener != null) {
						iOnItemCheckChangeListener.onItemCheckChange(aItem, aItem.getItem(), aChecked);
					}
				}

				if (aChecked) {
					addCheckedItem(aItem.getItem());
				} else {
					if (iCheckedItems != null) {
						synchronized (iCheckedItems) {
							if (iCheckedItems.contains(aItem) == false) {
								iHandler.removeMessages(KMESSAGE_SET_CHECKED, aItem);

								iCheckedItems.remove(aItem.getItem());
							}
						}
					}
				}
			}

			return true;
		}
	};

	private OnItemCheckChangeListener<TYPE> iOnItemCheckChangeListener = null;

	public void setOnItemCheckChangeListener(OnItemCheckChangeListener<TYPE> aListener) {
		iOnItemCheckChangeListener = aListener;
	}

	private View.OnClickListener iItemClickListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			if (v instanceof ItemView<?>) {
				if (iOnItemClickListener != null) {
					iOnItemClickListener.onItemClick((ItemView<TYPE>) v, (TYPE) ((ItemView<TYPE>) v).getItem());
				}
			}
		}
	};

	private OnItemClickListenerr<TYPE> iOnItemClickListener = null;

	public void setOnItemClickListenerr(OnItemClickListenerr<TYPE> aListener) {
		iOnItemClickListener = aListener;
	}

	private View.OnLongClickListener iItemLongClickListener = new View.OnLongClickListener() {
		@Override
		public boolean onLongClick(View v) {
			if (v instanceof ItemView<?>) {
				if (iOnItemLongClickListener != null) {
					iOnItemLongClickListener.onItemLongClick((ItemView<TYPE>) v, (TYPE) ((ItemView<TYPE>) v).getItem());
				}
			}

			return true;
		}
	};

	private OnItemLongClickListener<TYPE> iOnItemLongClickListener = null;

	public void setOnItemLongClickListener(OnItemLongClickListener<TYPE> aListener) {
		iOnItemLongClickListener = aListener;
	}

	private void handleViewEvent(ItemView<TYPE> aView, boolean aUnhandle) {
		if (aView != null) {
			aView.setOnItemCheckChangeListener(aUnhandle ? null : iItemCheckChangeListener);

			aView.setOnClickListener(aUnhandle ? null : iItemClickListener);

			aView.setOnLongClickListener(aUnhandle ? null : iItemLongClickListener);
		}
	}

	protected abstract void onRemoveItem(TYPE aItem, ItemView<TYPE> aItemView);

	public void removeAllItems() {
		if (iItems != null) {
			if (iItems.size() > 0) {
				try {
					for (int i = 0; i < iItems.size(); i++) {
						if (iItemViews != null && iItemViews.size() > 0 && iItemViews.size() > i) {
							onRemoveItem(iItems.get(i), iItemViews.get(i));
						} else {
							onRemoveItem(iItems.get(i), null);
						}

						/* try { onRemoveItem(iItems.get(i), iItemViews.get(i)); } catch (Exception e) { UIUtils.postTaskSafely(new Runnable() {
						 * 
						 * @Override public void run() { Toast.makeText(getContext(), "null...", Toast.LENGTH_SHORT).show(); } }); } */
					}
				} catch (Exception e) {}

				/* if(iItems != null){ iItems.clear(); }
				 * 
				 * if(iItems != null){ iItemViews.clear(); } */

				// this.removeAllViews();

				/* try { iItems.clear(); iItemViews.clear(); this.removeAllViews(); } catch (Exception e) { UIUtils.postTaskSafely(new Runnable() {
				 * 
				 * @Override public void run() { Toast.makeText(getContext(), "...null", Toast.LENGTH_SHORT).show(); } }); } */
			}

			iItems.clear();
			if (iItemViews != null) {
				iItemViews.clear();
			}
		}
	}

	/* public void refresh(){ if (iItemViews != null){ int tColumns = 0; int tTop = 0, tLeft = 0; View tItem;
	 
	 for (int i = 0; i < iItemViews.size(); i++){ tItem = iItemViews.get(i);
	 
	 if (tItem != null){ tItem.setBackgroundColor(Color.TRANSPARENT); tItem.layout(tLeft, tTop, tLeft + iItemWidth, tTop + iItemHeight); tItem.postInvalidate();
	 
	 if (++tColumns == iColumns){ tColumns = 0; tLeft = 0; tTop += iItemHeight; }else{ tLeft += iItemWidth; } } } } }

	 @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig);
	 
	 iWidth = 0; iHeight = 0; }

	 private int getTotalHeight(){ if (iItemViews != null){ int tCount = iItemViews.size();
	 
	 if (tCount > 0 && iColumns > 0){ int tRows = tCount % iColumns;
	 
	 if (tRows > 0){ tRows = (tCount - tRows) / iColumns + 1; }else{ tRows = tCount / iColumns; }
	 
	 return tRows * iItemHeight; } }
	 
	 return 0; }

	 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int tHeight = getTotalHeight();
	 
	 if (changed || iNeedToRefresh){ if (b - t < tHeight){ this.layout(l, t, r, b + (tHeight - (b - t)));
	 
	 return; }else{ refresh();
	 
	 iNeedToRefresh = false; }
	 
	 if (this.getParent() != null && this.getParent() instanceof ScrollView){ ScrollView tParent = (ScrollView) this.getParent();
	 
	 if (tHeight > 0){ if (tParent.getHeight() + tParent.getScrollY() > tHeight){ tParent.scrollTo(tParent.getScrollX(), tHeight - tParent.getHeight()); } } } } }

	 private int CalcGridColumns(int aWidth){ DisplayMetrics tMetrics = Resources.getSystem().getDisplayMetrics(); float tWidth;
	 
	 if (tMetrics.densityDpi - tMetrics.xdpi >= 160){ tWidth = ((float)aWidth / tMetrics.densityDpi); //Unit: inch }else{ tWidth = ((float)aWidth / tMetrics.xdpi); //Unit: inch } tWidth = tWidth *
	 25.4f; //Unit: mm
	 
	 return (int) Math.rint(tWidth / 18f); //18mm is good for finger operate }
	 
	 private int CalcGridRows(int aHeight){ DisplayMetrics tMetrics = Resources.getSystem().getDisplayMetrics(); float tHeight;
	 
	 if (tMetrics.densityDpi - tMetrics.ydpi >= 160){ tHeight = ((float)aHeight / tMetrics.densityDpi); //Unit: inch }else{ tHeight = ((float)aHeight / tMetrics.ydpi); //Unit: inch } tHeight =
	 tHeight * 25.4f; //Unit: mm
	 
	 return (int) Math.rint(tHeight / 20f); //20mm is good for finger operate }

	 @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (w != 0 && h != 0){ if (iWidth == 0 || iHeight == 0){ iWidth = w; iHeight = h;
	 
	 if (iWidth > 0 && iHeight > 0){ iColumns = CalcGridColumns(iWidth); iRows = CalcGridRows(iHeight);
	 
	 iItemWidth = iWidth / iColumns; iItemHeight = iHeight / iRows; } }
	 
	 int tHeight = getTotalHeight();
	 
	 if (tHeight > 0){ if (h != tHeight){ h = tHeight;
	 
	 this.layout(0, 0, w, h); } } }
	 
	 super.onSizeChanged(w, h, oldw, oldh); }

	 public ItemView<TYPE> buildItemView(TYPE aItem){
	 
	 ItemView<TYPE> tView = genItemView(aItem);
	 
	 if (tView != null){ if (iItemViews == null){ iItemViews = new ArrayList<ItemView<TYPE>>(); }
	 
	 if (iItemViews.add(tView)){ if (iItemChangeListener != null){ iItemChangeListener.onNewItem(tView, aItem); }
	 
	 if (iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE){ tView.setCheckable(true);
	 
	 if (iCheckedItems != null){ synchronized(iCheckedItems){ if (iCheckedItems.contains(aItem)){ iHandler.removeMessages(KMESSAGE_SET_CHECKED, aItem);
	 
	 tView.setChecked(true); } } } }
	 
	 handleViewEvent(tView, false);
	 
	 }
	 
	 if (iChoiceMode != TCHOICE_MODE.ECHOICE_MODE_NONE){ tView.setCheckable(true);
	 
	 if (iCheckedItems != null){ synchronized(iCheckedItems){ if (iCheckedItems.contains(aItem)){ iHandler.removeMessages(KMESSAGE_SET_CHECKED, aItem);
	 
	 tView.setChecked(true); }else{ tView.setChecked(false); } } } } return tView; }
	 
	 return null;
	 
	 
	  } */

}
